package com.qiu.usercenter.manager;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.qiu.usercenter.common.ErrorCode;
import com.qiu.usercenter.config.AIConfig;
import com.qiu.usercenter.exception.ExceptionUtils;
import com.qiu.usercenter.model.domain.AiRequest.ChatMessage;
import com.qiu.usercenter.model.domain.AiRequest.Config;
import lombok.Data;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Response;
import org.apache.hc.client5.http.classic.methods.HttpPost;
import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.async.CloseableHttpAsyncClient;
import org.apache.hc.client5.http.impl.async.HttpAsyncClients;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.CloseableHttpResponse;
import org.apache.hc.core5.http.HttpEntity;
import org.apache.hc.core5.http.ParseException;
import org.apache.hc.core5.http.io.entity.EntityUtils;
import org.apache.hc.core5.http.io.entity.StringEntity;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.nio.charset.Charset;
import java.util.*;
import java.util.concurrent.TimeUnit;

import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;

import static jdk.nashorn.internal.runtime.regexp.joni.Config.log;

//@Configuration
//@ConfigurationProperties(prefix = "ai")
@Data
//@Service
public class ServiceRequests {
    private final CloseableHttpClient client;

    private final CloseableHttpAsyncClient asyncClient;
    private final Config config;
    private final RequestConfig requestConfig;
    private final ObjectMapper jsonMapper = new ObjectMapper();


    public static final String PATH_CHAT_COMPLETIONS = "/api/v1/chat/completions";


    public ServiceRequests(Config config) {
        this(HttpClientBuilder.create().build(),
                HttpAsyncClients.createDefault(),
                RequestConfig.DEFAULT, config);
    }

    public ServiceRequests(CloseableHttpClient client, CloseableHttpAsyncClient asyncClient, RequestConfig requestConfig, Config config) {
        this.client = client;
        this.asyncClient = asyncClient;
        this.config = config;
        this.requestConfig = requestConfig;
    }

    public Map<String, Object> chatCompletions(String chatId, boolean detail, Map<String, String> variables,
                                               List<ChatMessage> messages) {
        HashMap<String, Object> param = new HashMap<>();
        param.put("chatId", chatId);
        param.put("stream", false);
        param.put("detail", detail);
        param.put("variables", variables);
        param.put("messages", messages);

        try {
            String e = this.postRequest(PATH_CHAT_COMPLETIONS, param);
            return str2Map(e);
        } catch (Exception e) {
            ExceptionUtils.error(ErrorCode.Request_ERROR.getCode(), e.getMessage(), "【更换聊天室ID】【等待模型加载】");
        }
        return null;
    }

    private String postRequest(String path, Map<String, Object> p) {
        String ret = "";
        try {
            String url = this.combPath(path);
            HttpEntity body = this.combBody(p);
            HttpPost post = new HttpPost(url);
            post.setEntity(body);
            ret = handleResp(doRequest(path, post));
        } catch (Exception e) {
            ExceptionUtils.error(ErrorCode.Request_ERROR.getCode(), e.getMessage(), "【更换聊天室ID】【等待模型加载】");
        }

        return ret;
    }

    private String combPath(String path) {
        return this.config.getApiUrl() + path;
    }


    private HttpEntity combBody(Map<String, Object> p) throws UnsupportedEncodingException, JsonProcessingException {
        p.entrySet().removeIf((e) -> Objects.isNull(e.getValue()));
        return new StringEntity(jsonMapper.writeValueAsString(p), Charset.forName(config.getCharset()));
    }

    private String handleResp(CloseableHttpResponse response) {
        String respContent = null;
        try {
            respContent = this.readContent(response.getEntity(),
                    Objects.isNull(response.getEntity().getContentEncoding()) ? this.config.getCharset() : response.getEntity().getContentEncoding());
        } catch (IOException | ParseException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                if (Objects.nonNull(response)) {
                    EntityUtils.consume(response.getEntity());
                }
            } catch (IOException e) {
                System.out.println("error={}" + e.getLocalizedMessage());
            }

        }


        return respContent;
    }

    private String readContent(HttpEntity e, String charset) throws IOException, ParseException {
        return EntityUtils.toString(e, Objects.isNull(charset) ? this.config.getCharset() : charset);
    }

    private CloseableHttpResponse doRequest(String path, HttpUriRequestBase method) throws IOException, ParseException {
        CloseableHttpResponse response = null;

        String ret;
        try {
            method.setConfig(this.requestConfig);
            method.addHeader("Content-Type", "application/json");
            if (Objects.nonNull(this.config.getKey())) {
                if (Objects.equals(path, PATH_CHAT_COMPLETIONS)) {
                    method.setHeader("Authorization", "Bearer " + this.config.getChatKey());
                } else {
                    method.setHeader("Authorization", "Bearer " + this.config.getKey());
                }
            }


            response = this.client.execute(method);
        } catch (Exception e) {
            System.out.println("error={}" + e.getLocalizedMessage());
            throw new RuntimeException(e);
        }

        return response;
    }

    private Map<String, Object> str2Map(String s) {
        try {
            return this.jsonMapper.readValue(s, Map.class);
        } catch (JsonProcessingException e) {
            throw new RuntimeException(e);
        }
    }

}